home *** CD-ROM | disk | FTP | other *** search
/ Suzy B Software 2 / Suzy B Software CD-ROM 2 (1994).iso / new_file / mintprgs / mint112s / mint112s.lzh / intr.spp < prev    next >
Encoding:
Text File  |  1994-08-30  |  14.7 KB  |  577 lines

  1. ; Copyright 1992 Eric R. Smith
  2. ; Copyright 1993,1994 Atari Corporation
  3. ; All rights reserved.
  4.  
  5. %include "magic.i"
  6. ;
  7. ; interrupt wrapping routines; these should just save registers and call
  8. ; the appropriate C handlers, unless speed is a major problem
  9. ;
  10.     TEXT
  11. ;
  12. ; first, utilities for setting processor status level
  13. ;
  14.     XDEF    _spl7
  15.     XDEF    _spl
  16. _spl7:
  17.     move.w    sr,d0
  18.     ori.w    #$0700,sr
  19.     rts
  20. _spl:
  21.     move.w    4(sp),sr
  22.     rts
  23.  
  24.     XDEF    _mint_5ms
  25.     XDEF    _mint_timer
  26.     XDEF    _mint_vbl
  27.     XREF    _timeout    ; C time routine
  28.     XREF    _old_timer    ; old GEMDOS time vector
  29.     XREF    _old_vbl    ; old GEMDOS vbl vector
  30.     XREF    _old_5ms
  31.     XREF    _build_context
  32.     XREF    _restore_context
  33.     XREF    _proc_clock        ; controls process' allocation of CPU time
  34.     XREF    _curproc
  35.     XREF    _enter_kernel
  36.     XREF    _leave_kernel
  37.     XREF    _preempt
  38.     XREF    _in_kernel
  39.     XREF    _calc_load_average
  40.     XREF    _uptimetick
  41.     XREF    _checkbttys_vbl
  42.  
  43. ; AKP: this code is hit once every 5ms; it updates the time fields of curproc.
  44. _mint_5ms:
  45.     move.l    a0,-(sp)
  46.     subq.w    #1,_uptimetick
  47.     move.l    _curproc,a0
  48.     tst.w    _in_kernel
  49.     bne.s    L_systime
  50.     addq.l    #5,P_USRTIME(a0)    ; update curproc->usrtime
  51.     move.l    (sp)+,a0
  52.     move.l    _old_5ms+8,-(sp)    ; branch to old vector
  53.     rts
  54. L_systime:
  55.     addq.l    #5,P_SYSTIME(a0)    ; update curproc->systime
  56.     move.l    (sp)+,a0
  57.     move.l    _old_5ms+8,-(sp)
  58.     rts
  59.  
  60. _mint_timer:
  61.     movem.l    d0-d2/a0-a2,-(sp)    ; save C registers
  62.     jsr    _timeout
  63.     movem.l    (sp)+,d0-d2/a0-a2
  64.     move.l    _old_timer+8,-(sp)    ; jump to GEMDOS time vector
  65.     rts
  66.  
  67. _mint_vbl:
  68. %ifndef ONLY030
  69.     tst.w    ($59e).w        ; test longframe (AKP)
  70.     beq.s    L_short1
  71. %endif
  72.     clr.w    -(sp)            ; yes, long frames: push a frame word
  73. L_short1:
  74.     pea    L_comeback(pc)        ; push fake PC
  75.     move.w    sr,-(sp)        ; push status register
  76.     move.l    _old_vbl+8,-(sp)    ; go service the interrupt
  77.     rts
  78.  
  79. L_comeback:
  80.     movem.l    d0-d2/a0-a2,-(sp)    ; save C registers
  81.     jsr    _checkbttys_vbl
  82.     tst.w    _uptimetick
  83.     bgt.s    L_no_uptime
  84.     jsr    _calc_load_average    ; Go test if it's time to update uptime
  85. L_no_uptime:
  86.     movem.l    (sp)+,d0-d2/a0-a2
  87.     tst.w    _proc_clock        ; has time expired yet?
  88.     beq.s    L_expired        ; yes -- maybe go switch processes
  89. L_out:
  90.     rte                ; no -- just return
  91.  
  92. L_expired:
  93.     btst    #5,(sp)            ; user mode?
  94.     bne.s    L_out            ; no -- switching is not possible
  95.     tst.w    ($43e).w        ; test floppy disk lock variable
  96.     bne.s    L_out            ; if locked, can't switch
  97.     tst.w    _in_kernel        ; are we doing a kernel operation?
  98.     bne.s    L_out
  99. L_switch:
  100.     clr.w    -(sp)            ; no frame format needed
  101.     move.l    _curproc,-(sp)
  102.     addq.l    #P_CTXT0,(sp)            ; to get &curproc->ctxt[SYSCALL]
  103.     jsr    _build_context        ; build context
  104.     move.l    _curproc,a0
  105.     move.l    (a0),sp            ; use curproc->sysstack
  106.     move.w    P_CTXT0+C_SR(a0),d7    ; get saved int level
  107. %ifdef ONLY030
  108.     clr.w    -(sp)            ; not a system call
  109. %else
  110.     move.w    #0,-(sp)        ; not a system call
  111. %endif
  112.     jsr    _enter_kernel        ; enter kernel
  113.     addq.w    #2,sp
  114.     move.w    sr,d1
  115.     eor.w    d1,d7
  116.     and.w    #$700,d7
  117.     eor.w    d7,d1
  118.     move.w    d1,sr            ; vbl allowed again
  119.     jsr    _preempt        ; yield processor
  120.     ori.w    #$700,sr        ; spl7()
  121.     jsr    _leave_kernel        ; restore vectors
  122.     move.l    _curproc,a0
  123.     pea    4(a0)
  124.     jsr    _restore_context    ; back to user
  125.  
  126. ;
  127. ; reset routine -- called on a warm boot. Note that TOS sends the
  128. ; address to which we should return in register a6. Also note that
  129. ; the stack pointer is in an unknown state, so we set up our own
  130. ;
  131.     XDEF    _reset
  132.     XREF    _init_tail        ; see main.c
  133.     XREF    _restr_intr
  134.  
  135. _reset:
  136.     move.w    #$2700,sr        ; avoid interruption here
  137.     move.l    sp,_init_tail        ; save A7
  138.     lea    _init_tail+256,sp    ; set up temporary stack
  139.     movem.l    d0-d2/a0-a2,-(sp)    ; save C registers
  140.     jsr    _restr_intr        ; restore interrupts
  141.     movem.l    (sp)+,d0-d2/a0-a2    ; restore registers
  142.     move.l    _init_tail,sp
  143.     jmp    (a6)            ; reset again
  144.  
  145. ;
  146. ; routine for doing a reboot
  147. ;
  148.     XDEF    _reboot
  149. _reboot:
  150.     move.w    #$2700,sr        ; avoid interrupts
  151.     move.l    (0).w,sp        ; get sp after reboot
  152.     move.l    (4).w,a6        ; get new reboot address
  153.     jmp    _reset
  154.  
  155. ;
  156. ; routine for mouse packet handling
  157. ;
  158.     XDEF    _newmvec
  159.     XDEF    _newjvec
  160.     XREF    _mouse_handler
  161. ; Experimental three button mouse support (by jr@ms.maus.de,
  162. ; August 4, 1992
  163. ;
  164. ; Should work with the mice shipped with Atari's ASV or
  165. ; compatible ones (like Golden Image GI-6000). Might not work
  166. ; on ST/STE systems with older IKBD's or keyboards. The middle mouse
  167. ; button is wired to one of the joystick directions on joystick one.
  168. ;
  169. ; _newmvec is the same as before with two exceptions:
  170. ; 1. the first byte of the packet is saved for the joystick handler
  171. ; 2. the bit for the middle mouse button is ored in
  172. ;
  173. ; _newjvec hooks into the joystick vector and chains to the normal
  174. ; handler. The middle mouse button state is saved in a special
  175. ; register for _newmvec, and a 'fake' mouse packet is set up
  176. ; (by merging the last mouse packet header, or-ing in the
  177. ; middle button state and using 0/0 for the x/y increment).
  178. ;
  179. ; the faked_packet and third_button variables are declared at the
  180. ; end of this file
  181.  
  182. _newmvec:
  183.     move.l    a0,-(sp)
  184.     move.b    (a0),d0
  185.     move.b    d0,faked_packet
  186.     or.b    third_button,d0
  187.     move.b    d0,(a0)
  188.     jsr    _mouse_handler
  189.     move.l    (sp)+,a0
  190.     rts
  191. ;
  192. ; routine for joystick packet handling (used for three button mice)
  193. ;
  194.     XDEF    _newjvec
  195.     XREF    _oldjvec
  196.  
  197. _newjvec:
  198.     move.l    a0,-(sp)    ; save a0 on the stack
  199.     move.b    2(a0),d0    ; joystick direction
  200.     and.b    #1,d0        ; middle mouse button in lowest bit
  201.     add.b    d0,d0        ; times 4
  202.     add.b    d0,d0
  203.     move.b    d0,third_button    ; save it for use in newmvec
  204.  
  205.     lea    faked_packet,a0    ; 'our' faked mouse event
  206.     move.b    (a0),d0
  207.     and.b    #$3,d0        ; unmask our mouse button
  208.     or.b    #$F8,d0        ; or in correct header
  209.     or.b    third_button,d0    ; or in the current status
  210.     move.b    d0,(a0)        ; write it back
  211.  
  212.     move.l    a0,-(sp)    ; pass pointer to fake packet
  213.     jsr    _mouse_handler    ; to \dev\mouse handler
  214.     addq.l    #4,sp        ; pop parameter
  215.     move.l    (sp)+,a0    ; restore original a0 value
  216.     move.l    _oldjvec,-(sp)    ; jump to original joystick handler
  217.     rts
  218. ;
  219. ; new ikbd keyboard interrupt vector
  220. ; kintr is a global variable that should be non-zero if a keyboard
  221. ; event occured
  222. ;
  223.     XDEF    _new_ikbd
  224.     XREF    _old_ikbd
  225.     XREF    _kintr
  226.  
  227. _new_ikbd:
  228.     move.w    #1,_kintr
  229.     move.l    _old_ikbd+8,-(sp)
  230.     rts            ; jump to system interrupt routine
  231.  
  232. ; Generic routine for handling any user-specified interrupts. On 68000, the
  233. ; vector number is stored in the high byte of the program counter.
  234. ;
  235.     XDEF    _new_intr
  236.     XDEF    _sig_user
  237.  
  238. _new_intr:
  239.     movem.l    d0-d2/a0-a2,-(sp)    ; save regs
  240.  
  241. %ifndef ONLY030
  242.     tst.w    ($59e).w    ; is frame format on stack?
  243.     bne.s    nvec        ; yes, go use it
  244.     bsr.s    ndummy        ; push PC to stack
  245.     nop
  246. ndummy:    
  247.     move.w    (sp)+,d0    ; pop hi(PC) to d0
  248.     addq.w    #2,sp        ; pop lo(PC) off stack
  249.     lsr.w    #8,d0        ; move hi byte to vector number
  250.     bra.s    ngot        ; continue
  251. nvec:
  252. %endif
  253.     move.w    30(sp),d0    ; get frame word
  254.     lsr.w    #2,d0        ; move vector offset to vector number
  255. ngot:
  256.     move.w    d0,-(sp)    ; push vector offset
  257.     jsr        _sig_user    ; send signal
  258.     addq.w    #2,sp            ; pop vector offset
  259.     movem.l    (sp)+,d0-d2/a0-a2    ; restore regs
  260.     rte
  261.  
  262. ;
  263. ; simple signal handlers
  264. ; global variables referenced:
  265. ; in_kernel: (main.c): flag to indicate that we're in the MiNT kernel
  266. ; sig_routine: (signal.c): pointer to which signal catching routine to
  267. ;          call (e.g. for SIGBUS, or whatever)
  268. ;
  269.     XDEF    _new_bus,_new_addr,_new_ill,_new_divzero,_new_priv,_new_linef
  270.     XDEF    _new_trace,_new_chk,_new_trapv,_new_fpcp,_new_mmu,_new_pmmuacc
  271.     XDEF    _new_uninit,_new_spurious,_new_format,_new_cpv
  272.     XREF    _in_kernel,_sig_routine
  273.     XREF    _sigbus,_sigaddr,_sigill,_sigfpe,_sigpriv,_sigtrap
  274.     XREF    _haltformat,_haltcpv
  275.     XREF    _sig_exc
  276.     XREF    _mcpu
  277.     
  278. ;
  279. ; New bus error handler for memory protection: get the ssp and
  280. ; put it in the proc structure before calling
  281. ; _sigbus.  When the bus error happens in the kernel we don't save
  282. ; any contexts.
  283. ; We don't want to mess up any registers here because we might bring the
  284. ; page in and RTE.
  285. ;
  286.  
  287. _new_bus:
  288. %ifndef ONLY030
  289.     move.w    #$8,_sig_exc
  290.     cmp.l    #30,_mcpu
  291.     bne.s    noMMU
  292. %endif
  293.     move.l    #_mmu_sigbus,_sig_routine
  294. %ifndef ONLY030
  295.     bra.s    Do_sig
  296. noMMU:
  297.     move.l    #_nommu_sigbus,_sig_routine
  298. %endif
  299. Do_sig:
  300.     move.l    a0,-(sp)        ; save a0
  301.     move.l    _curproc,a0
  302.     move.l    sp,P_EXCSSP(a0)
  303.     addq.l    #4,P_EXCSSP(a0)
  304.     move.l    6(sp),P_EXCPC(a0)
  305.     move.l    (sp)+,a0
  306.  
  307.     tst.w    _in_kernel        ; are we already in the kernel?
  308.     bne.s    Kernel            ; yes
  309.     move.w    _sig_exc,-(sp)
  310.     move.l    _curproc,-(sp)
  311.     addq.l    #4,(sp)            ; push offset of save area
  312.     jsr    _build_context
  313.     move.l    _curproc,a4
  314.     move.l    (a4),sp            ; put us in the system stack
  315. %ifdef ONLY030
  316.     clr.w    -(sp)            ; not a GEMDOS call
  317. %else
  318.     move.w    #0,-(sp)        ; not a GEMDOS call
  319. %endif
  320.     jsr    _enter_kernel        ; set up kernel vectors
  321.     addq.w    #2,sp
  322.     move.l    _sig_routine,a1        ; get signal handling routine
  323.     jsr    (a1)            ; go do it
  324.     ori.w    #$0700,sr        ; spl7()
  325.     jsr    _leave_kernel        ; leave kernel
  326.     addq.w    #4,a4            ; get context save area address
  327.     move.l    a4,-(sp)        ; push it
  328.     jsr    _restore_context    ; restore the context
  329. ;
  330. ; here's what we do if we already were in the kernel
  331. ;
  332. Kernel:
  333.     movem.l    d0-d2/a0-a2,-(sp)    ; save reggies
  334.     move.l    _sig_routine,a1        ; get handler
  335.     jsr    (a1)            ; go do it
  336.     movem.l    (sp)+,d0-d2/a0-a2
  337.     rte
  338.  
  339. ;
  340. ; _mmu_sigbus: a pre-handler for _sigbus.  Check the reason for the bus
  341. ; error and report if it was a real access fault.
  342. ;
  343. _mmu_sigbus:
  344.     move.l    a2,-(sp)
  345.     move.l    _curproc,a0
  346.     move.l    P_EXCSSP(a0),a1        ; a1 is now exception_ssp
  347.     move.w    $A(a1),d0        ; d0 is SSR
  348.     move.l    $10(a1),a1        ; a1 is the access address
  349.     move.l    a1,P_EXCADDR(a0)    ; save the access address
  350.  
  351.     ptestr    d0,(a1),#7,a2        ; a2 is the table address
  352.     move.l    a2,P_EXCTBL(a0)        ; save table address in curproc
  353.     pmove    mmusr,P_EXCMMUSR(a0)    ; save resulting mmusr in curproc
  354.     move.l    (sp)+,a2
  355.     jmp    _sigbus        ; chain to bus-error handler
  356. %ifndef ONLY030
  357. ;
  358. ; _nommu_sigbus: handler for bus errors on machines without MMU
  359.  
  360. _nommu_sigbus:
  361.     move.l    _curproc,a0
  362.     move.l    P_EXCSSP(a0),a1
  363.     lea    $10(a1),a1        ; point to access address
  364.     tst.w    ($59e).w        ; test longframe
  365.     beq.s    NOMMU1
  366.     addq.w    #8,a1            ; on 68000, address is 8 bytes further
  367. NOMMU1:
  368.     move.l    (a1),P_EXCADDR(a0)    ; save the access address
  369.     jmp    _sigbus
  370. %endif
  371.  
  372. _new_addr:
  373. %ifndef ONLY030
  374.     move.w    #$c,_sig_exc
  375. %endif
  376.     move.l    #_sigaddr,_sig_routine
  377.     bra    Do_sig
  378. _new_ill:
  379. %ifndef ONLY030
  380.     move.w    #$10,_sig_exc
  381. %endif
  382.     move.l    #_sigill,_sig_routine
  383.     bra    Do_sig
  384. _new_divzero:
  385. %ifndef ONLY030
  386.     move.w    #$14,_sig_exc
  387. %endif
  388.     move.l    #_sigfpe,_sig_routine
  389.     bra    Do_sig
  390. _new_linef:
  391. %ifndef ONLY030
  392.     move.w    #$2c,_sig_exc
  393. %endif
  394.     move.l    #_sigill,_sig_routine
  395.     bra    Do_sig
  396. _new_chk:
  397. %ifndef ONLY030
  398.     move.w    #$18,_sig_exc
  399. %endif
  400.     move.l    #_sigfpe,_sig_routine
  401.     bra    Do_sig
  402. _new_trapv:
  403. %ifndef ONLY030
  404.     move.w    #$1c,_sig_exc
  405. %endif
  406.     move.l    #_sigfpe,_sig_routine
  407.     bra    Do_sig
  408. _new_fpcp:
  409. ; don't set _sig_exc - only needed for 68000 vectors
  410.     move.l    #_sigfpe,_sig_routine
  411.     bra    Do_sig
  412. _new_mmu:
  413. ; don't set _sig_exc - only needed for 68000 vectors
  414.     move.l    #_sigill,_sig_routine
  415.     bra    Do_sig
  416. _new_pmmuacc:
  417. ; don't set _sig_exc - only needed for 68000 vectors
  418.     move.l    #_sigbus,_sig_routine
  419.     bra    Do_sig
  420. _new_uninit:
  421. %ifndef ONLY030
  422.     move.w    #$3c,_sig_exc
  423. %endif
  424.     move.l    #_sigbus,_sig_routine
  425.     bra    Do_sig
  426. _new_spurious:
  427. %ifndef ONLY030
  428.     move.w    #$60,_sig_exc
  429. %endif
  430.     move.l    #_sigbus,_sig_routine
  431.     bra    Do_sig
  432. _new_format:
  433.     move.l    #_haltformat,_sig_routine
  434.     bra    Do_sig
  435. _new_cpv:
  436.     move.l    #_haltcpv,_sig_routine
  437.     bra    Do_sig
  438.  
  439.     XREF    _old_priv        ; old privilege violation vector
  440. _new_priv:
  441. %ifndef ONLY030
  442.     move.w    #$20,_sig_exc
  443. %endif
  444.     move.l    #_sigpriv,_sig_routine
  445. %ifndef ONLY030
  446.     tst.w    ($59e).w        ; 68000s always get SIGPRIV
  447.     beq    Do_sig
  448. %endif
  449.     movem.l    d0/a0,-(a7)
  450.     move.l    10(a7),a0        ; fetch exception address
  451.     move.w    (a0),d0
  452.     and.w    #$ffc0,d0        ; partially decode move sr,...
  453.     cmp.w    #$40c0,d0        ; and test it
  454.     movem.l    (a7)+,d0/a0        ; preserves the flags
  455.     bne    Do_sig            ; doesn't look like sr,...
  456.     move.l    _old_priv+8,-(sp)    ; let our parent handle it
  457.     rts
  458.  
  459. ; XBRA vectors from main.c
  460.     XREF    _old_dos,_old_bios,_old_xbios
  461.     XREF    _old_divzero,_old_chk,_old_trapv
  462.  
  463. _new_trace:
  464.     btst    #5,(a7)            ; only check when called from supervisor mode
  465.     beq.s    S_1
  466.     cmp.l    #_old_dos+12,2(a7)    ; lets not trace the kernel !
  467.     beq.s    S_2
  468.     cmp.l    #_old_xbios+12,2(a7)
  469.     beq.s    S_2
  470.     cmp.l    #_old_bios+12,2(a7)
  471.     beq.s    S_2
  472.     cmp.l    #_old_divzero+12,2(a7)
  473.     beq.s    S_2
  474.     cmp.l    #_old_trapv+12,2(a7)
  475.     beq.s    S_2
  476.     cmp.l    #_old_chk+12,2(a7)
  477.     beq.s    S_2
  478. ; add any other non-traceable entities here...
  479.  
  480. S_1:    move.w    #$24,_sig_exc
  481.     move.l    #_sigtrap,_sig_routine
  482.     bra    Do_sig
  483.  
  484. S_2:    and.w    #$3fff,(a7)        ; clear both trace bits
  485.     rte                ; and re-start the handler
  486.  
  487. ;
  488. ; BIOS disk vectors for pseudo-disks like U: and X:; these are present
  489. ; just in case some program (foolishly) attempts to access these drives
  490. ; directly and gets horribly confused
  491. ;
  492.     XREF    _old_getbpb    ; old Getbpb vector
  493.     XREF    _old_mediach    ; old Mediach vector
  494.     XREF    _old_rwabs    ; old Rwabs vector
  495.     XREF    _aliasdrv    ; array of drive aliases
  496.     XDEF    _new_getbpb
  497.     XDEF    _new_mediach
  498.     XDEF    _new_rwabs
  499.  
  500. _new_getbpb:
  501.     move.w    4(sp),d0    ; check the drive
  502.     cmp.w    #$1f,d0        ; legal drive?
  503.     bhi.s    noalias0    ; no
  504.     move.w    d0,d1        ; get index
  505.     add.w    d0,d1        ; convert to index
  506.     lea    _aliasdrv,a0
  507.     move.w    0(a0,d1.w),d1    ; alias drive?
  508.     beq.s    noalias0
  509.     move.w    d1,d0
  510.     subq.w    #1,d0        ; adjust for aliasdrv base of '@'
  511.     cmp.w    #$1f,d0        ; is this a legal drive?
  512.     bhi.s    nobpb        ; no -- ignore it
  513. noalias0:
  514.     cmp.w    #$14,d0        ; drive U:?
  515.     beq.s    nobpb        ; yes, no BPB available
  516.     move.l    _old_getbpb+8,a0    ; not our drive
  517.     jmp    (a0)        ; call the old vector for it
  518. nobpb:
  519.     moveq.l    #0,d0        ; 0 means "no BPB read"
  520.     rts
  521.  
  522. _new_mediach:
  523.     move.w    4(sp),d0    ; check the drive
  524.     cmp.w    #$1f,d0        ; legal drive?
  525.     bhi.s    noalias1    ; no
  526.     move.w    d0,d1        ; get index
  527.     add.w    d0,d1        ; convert to index
  528.     lea    _aliasdrv,a0
  529.     move.w    0(a0,d1.w),d1    ; alias drive?
  530.     beq.s    noalias1
  531.     move.w    d1,d0
  532.     subq.w    #1,d0        ; adjust for aliasdrv base
  533.     cmp.w    #$1f,d0        ; legal drive?
  534.     bhi.s    nobpb        ; no -- ignore it
  535. noalias1:
  536.     cmp.w    #$14,d0        ; drive U:?
  537.     beq.s    nochng        ; yes, no change
  538.     move.l    _old_mediach+8,a0    ; not our drive
  539.     jmp    (a0)        ; call the old vector for it
  540. nochng:
  541.     moveq.l    #0,d0        ; 0 means "definitely no change"
  542.     rts
  543.  
  544. _new_rwabs:
  545.     move.w    $e(sp),d0    ; check the drive
  546.     cmp.w    #$1f,d0        ; legal drive?
  547.     bhi.s    noalias2    ; no
  548.     move.w    d0,d1        ; get index
  549.     add.w    d0,d1        ; convert to index
  550.     lea    _aliasdrv,a0
  551.     move.w    0(a0,d1.w),d1    ; alias drive?
  552.     beq.s    noalias2
  553.     move.w    d1,d0
  554.     subq.w    #1,d0        ; adjust for aliasdrv base
  555.     cmp.w    #$1f,d0        ; legal drive?
  556.     bhi.s    nobpb        ; no -- ignore it
  557. noalias2:
  558.     cmp.w    #$14,d0        ; drive U:?
  559.     beq.s    rwdone        ; yes, fake it
  560.     move.l    _old_rwabs+8,a0    ; not our drive
  561.     jmp    (a0)        ; call the old vector for it
  562. rwdone:
  563.     moveq.l    #0,d0        ; 0 means "successful operation"
  564.     rts
  565.  
  566.     DATA
  567. ; buffer for faked mouse packet (actually only 3 bytes)
  568.  
  569. faked_packet:
  570.     dc.l    0
  571.  
  572. ; here we store the additional button state
  573. third_button:
  574.     dc.w    0
  575.  
  576.     END
  577.